/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package eu.bopet.jocadv.core.datum;

import eu.bopet.jocadv.core.Element;
import eu.bopet.jocadv.core.Optimizable;
import eu.bopet.jocadv.core.Refreshable;
import eu.bopet.jocadv.core.VectorUtil;
import java.io.Serializable;
import java.util.Arrays;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;

/**
 *
 * The class represents datum planes in three dimensional space
 *
 * @author bocskapeter
 */
public class Plane extends Element implements Serializable, Refreshable, Optimizable {

    // Normal vector of the plane
    private Vector3D normal;

    // The value d for the plane equation: a * x + b * y + c * z + d = 0
    private double d;

    // Plane representation is a rectangle, defined by four points
    private final Vector3D[] rectangle = new Vector3D[4];

    /**
     * Builds a new plane on the given plane and with the given axis as normal
     * vector
     *
     * @param point as Vector3D
     * @param axis as Vector3D
     * @return new plane
     */
    public static Plane getNewPlane(Vector3D point, Vector3D axis) {
        Plane plane = new Plane("Plane");
        plane.setNormal(axis);
        plane.d = -1 * (axis.dotProduct(point));
        return plane;
    }

    /**
     * Default constructor
     *
     * @param name
     */
    public Plane(String name) {
        super(name);
    }

    /**
     * Gets the normal
     *
     * @return direction as Vector3D
     */
    public Vector3D getNormal() {
        return normal;
    }

    /**
     * Sets the normal
     *
     * @param normal as Vector3D
     */
    public void setNormal(Vector3D normal) {
        this.normal = normal;
    }

    /**
     * Gets the rectangle
     *
     * @return rectangle as Vector3D[]
     */
    public Vector3D[] getRectangle() {
        return rectangle;
    }

    /**
     * Converts to String
     *
     * @return Sting
     */
    @Override
    public String toString() {
        return "\n Plane{" + super.toString() + ", normal=" + normal + ", d=" + d + ", rectangle=" + Arrays.toString(rectangle) + '}';
    }

    /**
     * Refreshes the rectangle according to the geometric limits
     *
     * @param max - Maximum as Vector3D
     * @param min - Minimum as Vector3D
     */
    @Override
    public void refreshLimits(Vector3D max, Vector3D min) {
        int likeVector = VectorUtil.getIndexOfBiggestAbsCoord(this.getNormal().toArray());
        switch (likeVector) {
            // normal vector is in x axis direction
            case 0:
                rectangle[0] = new Vector3D(((normal.getY() * max.getY() + normal.getZ() * max.getZ() + d) / -normal.getX()), max.getY(), max.getZ());
                rectangle[1] = new Vector3D(((normal.getY() * min.getY() + normal.getZ() * max.getZ() + d) / -normal.getX()), min.getY(), max.getZ());
                rectangle[2] = new Vector3D(((normal.getY() * min.getY() + normal.getZ() * min.getZ() + d) / -normal.getX()), min.getY(), min.getZ());
                rectangle[3] = new Vector3D(((normal.getY() * max.getY() + normal.getZ() * min.getZ() + d) / -normal.getX()), max.getY(), min.getZ());
                break;
            // normal vector is in y axis direction
            case 1:
                rectangle[0] = new Vector3D(max.getX(), ((normal.getX() * max.getX() + normal.getZ() * max.getZ() + d) / -normal.getY()), max.getZ());
                rectangle[1] = new Vector3D(min.getX(), ((normal.getX() * min.getX() + normal.getZ() * max.getZ() + d) / -normal.getY()), max.getZ());
                rectangle[2] = new Vector3D(min.getX(), ((normal.getX() * min.getX() + normal.getZ() * min.getZ() + d) / -normal.getY()), min.getZ());
                rectangle[3] = new Vector3D(max.getX(), ((normal.getX() * max.getX() + normal.getZ() * min.getZ() + d) / -normal.getY()), min.getZ());
                break;
            // normal vector is in z axis direction
            case 2:
                rectangle[0] = new Vector3D(max.getX(), max.getY(), ((normal.getX() * max.getX() + normal.getY() * max.getY() + d) / -normal.getZ()));
                rectangle[1] = new Vector3D(min.getX(), max.getY(), ((normal.getX() * min.getX() + normal.getY() * max.getY() + d) / -normal.getZ()));
                rectangle[2] = new Vector3D(min.getX(), min.getY(), ((normal.getX() * min.getX() + normal.getY() * min.getY() + d) / -normal.getZ()));
                rectangle[3] = new Vector3D(max.getX(), min.getY(), ((normal.getX() * max.getX() + normal.getY() * min.getY() + d) / -normal.getZ()));
                break;
        }
    }

    /**
     * Gives the point (variables) of the equation
     *
     * @return array of double values
     */
    @Override
    public double[] getVaraiables() {
        return new double[]{this.normal.getX(), this.normal.getY(), this.normal.getZ(), this.d};
    }

}
